#include <stdbool.h>
#include <stdlib.h>
#include <sharp-linkedlist.h>

/*
struct sharp_linkedlist_s {
    void *data;
    sharp_linkedlist *prev;
    sharp_linkedlist *next;
};
*/

static bool createNode(sharp_linkedlist **node){
    sharp_linkedlist *tmpNode;

    *node = tmpNode = (sharp_linkedlist *)malloc(sizeof(sharp_linkedlist));
    if(tmpNode == NULL)
        return false;
    tmpNode->data = NULL;
    tmpNode->prev = tmpNode;
    tmpNode->next = tmpNode;
    return true;
}

bool sharp_linkedlist_init(sharp_linkedlist **list){
    *list = NULL;
    return true;
}

bool sharp_linkedlist_insert(sharp_linkedlist **list, void *data){
    sharp_linkedlist *newNode, *tmpList;

    if(!createNode(&newNode))
        return false;
    newNode->data = data;
    tmpList = *list;
    if(!sharp_linkedlist_isempty(tmpList)){
        newNode->next = tmpList;
        newNode->prev = tmpList->prev;
        tmpList->prev->next = newNode;
        tmpList->prev = newNode;
    }
    *list = newNode;
    return true;
}

bool sharp_linkedlist_append(sharp_linkedlist **list, void *data){
    sharp_linkedlist *newNode, *tmpList;

    if(!createNode(&newNode))
        return false;
    newNode->data = data;
    tmpList = *list;
    if(!sharp_linkedlist_isempty(*list)){
        newNode->next = tmpList;
        newNode->prev = tmpList->prev;
        tmpList->prev->next = newNode;
        tmpList->prev = newNode;
    }else{
        *list = newNode;
    }
    return true;
}

bool sharp_linkedlist_delete(sharp_linkedlist **list, sharp_linkedlist **node,
    void **data){
    sharp_linkedlist *tmpList, *newNode;

    if(!node)
        node = list;
    if(!list)
        list = node;
    if(!node)
        return false;
    tmpList = *node;
    if(sharp_linkedlist_isempty(tmpList))
        return false;
    newNode = tmpList->next;
    *data = tmpList->data;
    if(tmpList == newNode){
        free(tmpList);
        if(*list == *node){
            *list = NULL;
        }
        *node = NULL;
        return true;
    }
    newNode->prev = tmpList->prev;
    tmpList->prev->next = newNode;
    if(*list == *node){
        *list = newNode;
    }
    *node = newNode;
    free(tmpList);
    return true;
}

bool sharp_linkedlist_delete_last(sharp_linkedlist **list,
    sharp_linkedlist **node, void **data){
    sharp_linkedlist *tmpList, *lastNode;

    if(!node)
        node = list;
    if(!list)
        list = node;
    if(!node)
        return false;
    tmpList = *node;
    if(sharp_linkedlist_isempty(tmpList))
        return false;
    lastNode = tmpList->prev;
    *data = lastNode->data;
    if(tmpList == lastNode){
        free(tmpList);
        if(*list == *node){
            *list = NULL;
        }
        *list = NULL;
        return true;
    }
    lastNode->prev->next = tmpList;
    tmpList->prev = lastNode->prev;
    free(lastNode);
    return true;
}

bool sharp_linkedlist_destroy(sharp_linkedlist **list, 
    void (*destroy_data)(void *data)){
    void *tmpData;
    while(!sharp_linkedlist_isempty(*list)){
        sharp_linkedlist_delete(list, NULL, &tmpData);
        destroy_data(tmpData);
    }
    return true;
}

bool sharp_linkedlist_iter(sharp_linkedlist *list, sharp_linkedlist **next){
    if(list->prev == *next){
        *next = NULL;
        return false;
    }
    if(*next == NULL){
        *next = list;
        return true;
    }
    *next = (*next)->next;
    return true;
}

bool sharp_linkedlist_isempty(sharp_linkedlist *list){
    return (list == NULL) ? true : false;
}
